#include "U2ArchiveManager.h"

#include "U2LogManager.h"
#include "U2Exception.h"
#include "U2Archive.h"


U2EG_NAMESPACE_USING

//-----------------------------------------------------------------------
template<> U2ArchiveManager* U2Singleton<U2ArchiveManager>::s_pSingleton = 0;

U2ArchiveManager* U2ArchiveManager::getSingletonPtr(void)
{
    return s_pSingleton;
}

U2ArchiveManager& U2ArchiveManager::getSingleton(void)
{  
    assert( s_pSingleton );
    return ( *s_pSingleton );  
}
//-----------------------------------------------------------------------
U2ArchiveManager::U2ArchiveManager()
{
}

U2Archive* U2ArchiveManager::load( const U2String& filename, const U2String& archiveType)
{
	ArchiveMap::iterator i = mArchives.find(filename);
	U2Archive* pArch = 0;

	if (i == mArchives.end())
	{
		// Search factories
		ArchiveFactoryMap::iterator it = mArchFactories.find(archiveType);
		if (it == mArchFactories.end())
			// Factory not found
			U2_EXCEPT(U2Exception::ERR_ITEM_NOT_FOUND, "Cannot find an archive factory "
			"to deal with archive of type " + archiveType, "U2ArchiveManager::load");

		pArch = it->second->createInstance(filename);
		pArch->load();
		mArchives[filename] = pArch;

	}
	else
	{
		pArch = i->second;
	}
	return pArch;
}
//-----------------------------------------------------------------------
void U2ArchiveManager::unload(U2Archive* arch)
{
	unload(arch->getName());
}
//-----------------------------------------------------------------------
void U2ArchiveManager::unload(const U2String& filename)
{
	ArchiveMap::iterator i = mArchives.find(filename);

	if (i != mArchives.end())
	{
		i->second->unload();
		// Find factory to destroy
		ArchiveFactoryMap::iterator fit = mArchFactories.find(i->second->getType());
		if (fit == mArchFactories.end())
		{
			// Factory not found
			U2_EXCEPT(U2Exception::ERR_ITEM_NOT_FOUND, "Cannot find an archive factory "
				"to deal with archive of type " + i->second->getType(), "U2ArchiveManager::~U2ArchiveManager");
		}
		fit->second->destroyInstance(i->second);
		mArchives.erase(i);
	}
}
//-----------------------------------------------------------------------
U2ArchiveManager::ArchiveMapIterator U2ArchiveManager::getArchiveIterator(void)
{
	return ArchiveMapIterator(mArchives.begin(), mArchives.end());
}
//-----------------------------------------------------------------------
U2ArchiveManager::~U2ArchiveManager()
{
	// Unload & delete resources in turn
	for( ArchiveMap::iterator it = mArchives.begin(); it != mArchives.end(); ++it )
	{
		U2Archive* arch = it->second;
		// Unload
		arch->unload();
		// Find factory to destroy
		ArchiveFactoryMap::iterator fit = mArchFactories.find(arch->getType());
		if (fit == mArchFactories.end())
		{
			// Factory not found
			U2_EXCEPT(U2Exception::ERR_ITEM_NOT_FOUND, "Cannot find an archive factory "
				"to deal with archive of type " + arch->getType(), "U2ArchiveManager::~U2ArchiveManager");
		}
		fit->second->destroyInstance(arch);

	}
	// Empty the list
	mArchives.clear();
}
//-----------------------------------------------------------------------
void U2ArchiveManager::addArchiveFactory(U2ArchiveFactory* factory)
{        
	mArchFactories.insert( ArchiveFactoryMap::value_type( factory->getType(), factory ) );
	U2LogManager::getSingleton().logMessage("ArchiveFactory for archive type " + factory->getType() + " registered.");
}